﻿/*  2008 R2 Object Explorer support.
 * see this blog
   http://blog.sqlblog.com/blogs/jonathan_kehayias/archive/2009/08/22/sql-2008-r2-breaks-ssms-addins.aspx
 you used to be able to hook up to the object explorer but now it just doesnt want to work
 * every interface or code snippet that is suggested no longer works as it either doesnt exist
 * or it is null, so to try again later add these references and uncomment the GetObjectExplorer method
 
     <Reference Include="Microsoft.SqlServer.SqlTools.VSIntegration">
      <HintPath>C:\Program Files (x86)\Microsoft SQL Server\100\Tools\Binn\VSShell\Common7\IDE\Microsoft.SqlServer.SqlTools.VSIntegration.dll</HintPath>
    </Reference>
    <Reference Include="Microsoft.VisualStudio.OLE.Interop, Version=7.1.40304.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
      <SpecificVersion>False</SpecificVersion>
      <HintPath>C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\PrivateAssemblies\Microsoft.VisualStudio.OLE.Interop.dll</HintPath>
    </Reference>
    <Reference Include="ObjectExplorer">
      <HintPath>C:\Program Files (x86)\Microsoft SQL Server\100\Tools\Binn\VSShell\Common7\IDE\ObjectExplorer.dll</HintPath>
    </Reference>
    <Reference Include="SqlWorkbench.Interfaces">
      <HintPath>C:\Program Files (x86)\Microsoft SQL Server\100\Tools\Binn\VSShell\Common7\IDE\SqlWorkbench.Interfaces.dll</HintPath>
    </Reference>
 * 
 // trying to get this to work only reason its in here is to use IObjectExplorer which doesnt work anymore since R2 so stuck
using Microsoft.SqlServer.Management.UI.VSIntegration.ObjectExplorer;
using Microsoft.SqlServer.Management.UI.VSIntegration;
 
OR: PASTE This in PyPad
 * 
 import clr
clr.AddReferenceToFileAndPath(r"C:\Program Files (x86)\Microsoft SQL Server\100\Tools\Binn\VSShell\Common7\IDE\Microsoft.SqlServer.SqlTools.VSIntegration.dll")
clr.AddReferenceToFileAndPath(r"C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\PrivateAssemblies\Microsoft.VisualStudio.OLE.Interop.dll");
clr.AddReferenceToFileAndPath(r"C:\Program Files (x86)\Microsoft SQL Server\100\Tools\Binn\VSShell\Common7\IDE\ObjectExplorer.dll")
clr.AddReferenceToFileAndPath(r"C:\Program Files (x86)\Microsoft SQL Server\100\Tools\Binn\VSShell\Common7\IDE\SqlWorkbench.Interfaces.dll")

from Microsoft.SqlServer.Management.UI.VSIntegration.ObjectExplorer import *
from Microsoft.SqlServer.Management.UI.VSIntegration import *
  
 * and waste some time and then some more time
 */

using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using ACSR.SqlServer.AddIn.Core.Interface;
using EnvDTE;
using Extensibility;
using EnvDTE80;
using ACSR.SqlServer.Addin.Core.UI;
using ACSR.SqlServer.AddIn.Core.Interfaces;
using System.Collections.Generic;


namespace ACSR.SqlServer.AddIn.Core.Controllers
{
    public class AddInController : IAddInController
    {
        [DllImport("user32.dll")]
        public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

        public static string MessageTypeToString(MessageType msgType)
        {
            switch (msgType)
            {
                case MessageType.Message:
                    return "Message";
                case MessageType.Warning:
                    return "Warning";
                case MessageType.Error:
                    return "Error";
                default:
                    return "Unknown";
            }
        }

        private DTE2 _applicationObject;
        private EnvDTE.AddIn _addInInstance;

        public EnvDTE.AddIn AddInInstance
        {
            get
            {
                return _addInInstance;
            }
        }

        public DTE2 ApplicationObject
        {
            get
            {
                return _applicationObject;
            }
        }

        CommandEvents _CommandEvents;

        public CommandEvents CommandEvents
        {
            get
            {
                return _CommandEvents;
            }
        }

        public event _dispCommandEvents_BeforeExecuteEventHandler OnBeforeExecute;
        public event _dispCommandEvents_AfterExecuteEventHandler OnAfterExecute;

        protected string WorkingDirectory
        {
            get
            {
                return _workingDirectory;
            }
        }

        public AddInController(object addInInst)
        {
            _addInInstance = (EnvDTE.AddIn)addInInst;
            _applicationObject = (DTE2)_addInInstance.DTE;

            _workingDirectory = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
            _uiDLL = Path.Combine(_workingDirectory, "ACSR.SqlServer.Addin.Core.UI.dll");

            _CommandEvents = _applicationObject.Events.get_CommandEvents("{52692960-56BC-4989-B5D3-94C47A513E8D}", 1);
            _CommandEvents.AfterExecute += new _dispCommandEvents_AfterExecuteEventHandler(_CommandEvents_AfterExecute);
            _CommandEvents.BeforeExecute += new _dispCommandEvents_BeforeExecuteEventHandler(_CommandEvents_BeforeExecute);

        }


        public dynamic AddNamedCommand(string name, string buttonText, string toolTip, int ImageId)
        {
            try
            {

                object[] contextGUIDS = new object[] { };
                int commandStatus = (int)vsCommandStatus.vsCommandStatusSupported +
                    (int)vsCommandStatus.vsCommandStatusEnabled;
                int commandStyle = (int)vsCommandStyle.vsCommandStylePictAndText;

                dynamic commands = _addInInstance.DTE.Commands;
                dynamic cmdResult = commands.AddNamedCommand2(_addInInstance, name,
                buttonText, toolTip, true, ImageId,
                ref contextGUIDS,
                commandStatus,
                commandStyle,
                vsCommandControlType.vsCommandControlTypeButton);
                return cmdResult;
            }
            catch (Exception x)
            {
                LogError("AddNamedCommand() Error: " + x.Message);
                return null;
            }
        }

        List<Command> FindCommands(string commandName)
        {
            try
            {
                var commandItems = new List<Command>();

                foreach (Command cmd in _addInInstance.DTE.Commands)
                {
                    if (cmd.Name.ToString().Contains(commandName))
                    {
                        commandItems.Add(cmd);
                    }
                }
                return commandItems;
            }
            catch (Exception e)
            {
                LogError("Error AddInController.FindCommands: " + e.Message);
                throw;
            }
        }
         void RemoveCommands(string commandName)
         {
             try
             {
                 var commandItems = FindCommands(commandName);
                 foreach (Command cmd in commandItems)
                 {
                     try
                     {
                         LogMessage("deleting:" + cmd.Name);
                         cmd.Delete();
                     }
                     catch (Exception e)
                     {
                         LogError("Error AddInController.RemoveCommands.Delete: " + e.Message);
                         //throw;
                     }
                 }
             }
             catch (Exception e)
             {
                 LogError("Error AddInController.RemoveCommands: " + e.Message);
                 throw;
             }
         }
        dynamic _menuCommandBar = null;

            dynamic GetCommandBars()
            {
                return _addInInstance.DTE.CommandBars;
            }
        
            dynamic GetMenuCommandBar()
            {
                if (_menuCommandBar == null)
                {
                    _menuCommandBar = GetCommandBars()["MenuBar"];
                }
                if (_menuCommandBar == null)
                    throw new Exception("Menu bar is null");

                
                return _menuCommandBar;
            }

            List<dynamic> FindCommandBarControls(dynamic menu, string commandBarName)
            {
                var menuItems = new List<dynamic>();
                foreach (var control in menu.CommandBar.Controls)
                {
                    if (control.Caption.ToString().Contains(commandBarName))
                    {
                        menuItems.Add(control) ;
                    }
                }
                return menuItems;
            }

            void RemoveCommandBarControls(dynamic menu, string commandBarName)
            {
                foreach (var control in FindCommandBarControls(menu, commandBarName))
                {
                    control.Delete();
                }
            }

            Commands GetCommands()
            {
                return _addInInstance.DTE.Commands;
            }

            dynamic AddCommandBar(dynamic menu, string name)
            {
                return GetCommands().AddCommandBar(name, 
                        vsCommandBarType.vsCommandBarTypeMenu, menu.CommandBar);
            }

        dynamic ReAddCommandBar(dynamic menu, string name)
        {
            RemoveCommandBarControls(menu, name);
            return AddCommandBar(menu, name);
        }

        dynamic  GetToolsMenuControl()
        {
            var tools = GetMenuCommandBar().Controls["Tools"];
            if (tools == null)
                throw new Exception("tools is null");
            return tools;
        }

        protected dynamic CreateCommandBar(string menuName)
        {
            try
            {
                return ReAddCommandBar(GetToolsMenuControl(), menuName);                
            }
            catch (Exception e)
            {
                LogError("Error AddInController.CreateCommandBar: " + e.Message);
                throw;
            }
        }

         public dynamic AddCommand(dynamic Bar, string name, string text, string toolTip, int imageIndex)
         {
             try
             {
                 RemoveCommands(name);
                 var cmd = AddNamedCommand(name, text, toolTip, 13);
                 cmd.AddControl(Bar, 1);
                 return cmd;
             }
             catch (Exception e)
             {
                 LogError("Error AddInController.AddCommand: " + e.Message);
                 throw;
             }
         }


        protected virtual void InternalCommandEvents_AfterExecute(string Guid, int ID, object CustomIn, object CustomOut)
        {

        }

        protected virtual void InternalCommandEvents_BeforeExecute(string Guid, int ID, object CustomIn, object CustomOut, ref bool CancelDefault)
        {

        }

        void _CommandEvents_AfterExecute(string Guid, int ID, object CustomIn, object CustomOut)
        {

            InternalCommandEvents_AfterExecute(Guid, ID, CustomIn, CustomOut);
        }

        void _CommandEvents_BeforeExecute(string Guid, int ID, object CustomIn, object CustomOut, ref bool CancelDefault)
        {
            InternalCommandEvents_BeforeExecute(Guid, ID, CustomIn, CustomOut, ref CancelDefault);
        }

       
        IToolWindowContext _logWindow = null;

        dynamic _logWindowControl = null;
        string _workingDirectory;
        private string _uiDLL;
        public string UIDll
        {
            get
            {
                return _uiDLL;
            }
        }

        public IToolWindowContext CreateToolWindow(string assemblyLocation, string typeName, string Caption, Guid uiTypeGuid)
        {
            Windows2 win2 = _applicationObject.Windows as Windows2;
            if (win2 != null)
            {
                object controlObject = null;

                Window toolWindow = win2.CreateToolWindow2(_addInInstance, assemblyLocation, typeName, Caption, "{" + uiTypeGuid.ToString() + "}", ref controlObject);
                Window2 toolWindow2 = (Window2)toolWindow;
                toolWindow.Linkable = false;
                //toolWindow.IsFloating = true;
                try
                {
                    toolWindow.WindowState = vsWindowState.vsWindowStateMaximize;
                }
                catch
                {
                }

                toolWindow.Visible = true;

                return new ToolWindowContext(toolWindow, toolWindow2, controlObject);
            }
            return null;
        }

        public void HostWindow(dynamic hostWindow, Control controlToHost)
        {
            hostWindow.HostChildControl(new ControlContext(controlToHost));
        }

        public IToolWindowContext CreateHostWindow(Control controlToHost, string caption, string guid)
        {
            controlToHost.Dock = System.Windows.Forms.DockStyle.Fill;
            controlToHost.Visible = true;
            var window = CreateCommonUIControl("ACSR.SqlServer.Addin.Core.UI.UcControlHost", caption, new Guid(guid));
            HostWindow(((dynamic)window.ControlObject), controlToHost);
            return window;
        }

        public IToolWindowContext CreateCommonUIControl(string typeName, string caption, Guid guid)
        {
            return CreateToolWindow(UIDll, typeName, caption, guid);
        }

        void CreateLogWindow()
        {
            _logWindow = CreateCommonUIControl("ACSR.SqlServer.Addin.Core.UI.UcLogWindow", "IronPython LogWindow", new Guid("3ADC13FF-DCF4-4C49-B2EF-3D78DECDC664"));
            _logWindowControl = ((dynamic)_logWindow.ControlObject);
        }

        public void InternalLogMessage(string message, MessageType messageType)
        {
            LogMessageToFile(message, messageType);
            LogMessageToWindow(message, messageType);
        }

        public void LogWarning(string warning)
        {
            InternalLogMessage(warning, MessageType.Warning);
        }

        public void LogMessage(string message)
        {
            InternalLogMessage(message, MessageType.Message);
        }

        public void LogError(string error)
        {
            LogMessageToFile(error, MessageType.Error);
            if (LogMessageToWindow(error, MessageType.Error))
            {
                return;
            }
            MessageBox.Show(error);
        }
        string FormatMessage(string message, MessageType messageType)
        {
            return string.Format("[{0:HH:MM:ss}][{1}]: {2}", DateTime.Now, MessageTypeToString(messageType), message);
        }
        bool LogMessageToWindow(string message, MessageType messageType)
        {
            if (_logWindowControl != null)
            {
                string msg = FormatMessage(message, messageType) + System.Environment.NewLine;
                _logWindowControl.LogRawMessage(msg);
                return true;
            }
            return false;
        }
        void LogMessageToFile(string message, MessageType messageType)
        {
            System.IO.StreamWriter sw = System.IO.File.AppendText(_logFileName);
            try
            {
                sw.WriteLine(FormatMessage(message, messageType));
            }
            finally
            {
                sw.Close();
            }
        }
        string _logFileName;

        void CreateLogFile()
        {
            try
            {
                _logFileName = Path.Combine(_workingDirectory, "PyAddIn.Log");
                LogMessage("Log File Created");
            }
            catch (Exception e)
            {
                LogError("Error CreateLogFile:" + e.Message);
            }

        }



        

        private void InitLogWindow()
        {
            try
            {
                CreateLogWindow();
                string assemblyName = Path.GetFileName(System.Reflection.Assembly.GetExecutingAssembly().Location);
                LogMessage(string.Format("Controller Loaded:{0} - {1}", _workingDirectory, assemblyName));

            }
            catch (Exception e)
            {
                LogError("Error InitLogWindoww: " + e.Message);
            }
        }    



        

        

      //  object _objectExplorer = null;

        protected virtual void InternalOnConnectionCompleted()
        {
        }

        public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom)
        {
            try
            {
                CreateLogFile();

                InitLogWindow();
                InternalOnConnectionCompleted();

                LogMessage("Controller Connected");
            }
            catch (Exception e)
            {
                LogError("Error AddInController.OnConnection: " + e.Message);
            }
        }


        protected virtual void InternalOnDisconnectionCompleted(ext_DisconnectMode disconnectMode, ref Array custom)
        {

        }

        public void OnDisconnection(ext_DisconnectMode disconnectMode, ref Array custom)
        {
            this.InternalOnDisconnectionCompleted(disconnectMode, ref custom);
           
        }

        protected virtual void InternalOnAddInsUpdateCompleted(ref Array custom)
        {

        }

        public void OnAddInsUpdate(ref Array custom)
        {
            this.InternalOnAddInsUpdateCompleted(ref custom);
        }

        protected virtual void InternalOnStartupCompleteCompleted(ref Array custom)
        {

        }

        public void OnStartupComplete(ref Array custom)
        {
            try
            {
                _logWindow.Window.Visible = true;
            }
            catch (Exception e)
            {
                LogError("Error OnStartupComplete: " + e.Message);
            }
            this.InternalOnStartupCompleteCompleted(ref custom);

        }

        protected virtual void InternalOnBeginShutdownCompleted(ref Array custom)
        {

        }

        public void OnBeginShutdown(ref Array custom)
        {
            this.InternalOnBeginShutdownCompleted(ref custom);
            

        }

        protected virtual void InternalExec(string CmdName, vsCommandExecOption ExecuteOption, ref object VariantIn, ref object VariantOut, ref bool Handled)
        {

        }

        public void Exec(string CmdName, vsCommandExecOption ExecuteOption, ref object VariantIn, ref object VariantOut, ref bool Handled)
        {
            this.InternalExec(CmdName, ExecuteOption, ref VariantIn, ref VariantOut, ref Handled);
          

        }

        protected virtual void InternalQueryStatus(string CmdName, vsCommandStatusTextWanted NeededText, ref vsCommandStatus StatusOption, ref object CommandText)
        {

        }

        public void QueryStatus(string CmdName, vsCommandStatusTextWanted NeededText, ref vsCommandStatus StatusOption, ref object CommandText)
        {

            if (NeededText == vsCommandStatusTextWanted.vsCommandStatusTextWantedNone)
            {
                this.InternalQueryStatus(CmdName, NeededText, ref StatusOption, ref CommandText);
            }
             StatusOption = vsCommandStatus.vsCommandStatusSupported | vsCommandStatus.vsCommandStatusEnabled;
                CommandText = "TestCommandText";

        }
    }

    public class ToolWindowContext : IToolWindowContext
    {
        public Window Window { get; set; }
        public Window Window2 { get; set; }
        public dynamic ControlObject { get; set; }
        public ToolWindowContext(Window Window, Window2 Window2, dynamic ControlObject)
        {
            this.Window = Window;
            this.Window2 = Window2;
            this.ControlObject = ControlObject;
        }
    }


}
